interface CallbackFrame {
	frame: number;
	callback: () => void;
	self: any;
}

class MainWindow extends eui.UILayer {
	private static instance: MainWindow;

	public static ins(): MainWindow {
		if (!this.instance) {
			this.instance = new MainWindow();
		}
		return this.instance;
	}

	// 注册TOUCH_MOVE,TOUCH_END事件！
	drag: MainDrag;

	bindDrag(o: egret.DisplayObject, inMap: boolean): void {
		this.drag.bindDrag(o, inMap);
	}

	// 注册TOUCH_END
	hold: MainHold;

	// 注册TOUCH_BEGIN
	dbclick: MainDoubleClick;

	// 注册TOUCH_END
	mode: MainMode;

	// 注册TOUCH_TAP
	focus: MainFocus;

	// 注册window.document.mousemove
	cursor: MainCursor;

	// 注册div.ondrop
	drop: MainDrop;

	// window.document.mousedown
	rightclick: MainRightClick;

	modal: MainModal;

	constructor() {
		super();
		this.drag = new MainDrag(this);
		this.hold = new MainHold(this);
		this.dbclick = new MainDoubleClick(this);
		this.focus = new MainFocus(this);
		this.mode = new MainMode(this);
		this.drop = new MainDrop(this);
		this.rightclick = new MainRightClick(this);
	}

	override childrenCreated(): void {
		super.childrenCreated();

		window.document.addEventListener('keydown', (ev: KeyboardEvent) =>
			this.onWindowKey(ev, 'down'),
		);
		window.onerror = function myErrorHandler(
			event: string,
			source: string,
			lineno: number,
		): boolean {
			ui.msgerror('window.onerror: ', event); // or any message
			ui.msgerror(source, lineno); // or any message
			return false;
		};
		// window.addEventListener('unhandledrejection', (event) => {
		// 	// ui.msgwarn('unhandledrejection', event?.reason?.message); // 打印"Unhandle Promise Error!"
		// });

		// window.addEventListener('rejectionhandled', (event) => {
		// 	// ui.msgwarn('rejectionhandled', event); // 1秒后打印"rejection handled"
		// });

		mouse.enable(this.stage);
		mouse.setMouseMoveEnabled(true);

		// this.createLayers();

		this.addEventListener(egret.TouchEvent.ENTER_FRAME, this.onEnterFrame, this);
		this.addEventListener(egret.Event.ENTER_FRAME, this.onEnterFrameLast, this, false, -10000);
		this.stage.addEventListener(mouse.MouseEvent.MOUSE_WHEELTOP, this.onMouseWheel, this);
	}

	getMousePos(): [number, number] {
		return [mouse.mouseX, mouse.mouseY];
	}

	getMouseHit(): egret.DisplayObject {
		const [mx, my] = this.getMousePos();
		return this.stage.$hitTest(mx, my);
	}

	onMouseWheel(ev: egret.Event): void {
		const target = this.getMouseHit();
		if (target) {
			target.dispatchEventWith(mouse.MouseEvent.MOUSE_WHEEL, true, ev.data);
		}
	}

	nextFrame(listener: () => void, thisObject: any): void {
		this.nextFrameNum(1, listener, thisObject);
	}

	nexts: CallbackFrame[] = [];

	nextFrameNum(frame: number, callback: () => void, self: any): void {
		if (frame >= 1) {
			this.nexts.push({ frame, callback, self });
		}
	}

	callNextTimer(): void {
		const { nexts } = this;
		this.nexts = [];

		for (const n of nexts) {
			n.frame--;
			if (n.frame === 0) {
				try {
					n.callback.apply(n.self);
				} catch (error) {
					console.error('callTimer', error);
					console.trace();
				}
			} else {
				this.nexts.push(n);
			}
		}
	}

	onEnterFrame(): void {
		// https://bbs.egret.com/forum.php?mod=viewthread&tid=50502&highlight=%E5%8D%A1%E6%AD%BB
		try {
			this._onEnterFrame();
			this.updateGpuMem();
			this.callNextTimer();
		} catch (e) {
			/// console.error(e);
			ui.msgerror('onEnterFrame', e);
		}
	}

	updateGpuMem() {
		const mem = Math.floor(RES.gpuSize() / 1024 / 1024);
		const fps = egret['web']['WebFps'];
		fps.setGpuSize(mem);
		// fps['gpuSize'] = mem;
		// egret.
	}

	prevTimer = 0;

	_onEnterFrame(): void {
		if (this.prevTimer === 0) {
			this.prevTimer = egret.getTimer();
		}

		const t = egret.getTimer();
		let delta = t - this.prevTimer;
		this.prevTimer = t;
		if (delta <= 0) {
			delta = 1;
		}

		PixelShaderMan.ins().doUpdate(delta);
	}

	onEnterFrameLast(): void {
		// https://bbs.egret.com/forum.php?mod=viewthread&tid=50502&highlight=%E5%8D%A1%E6%AD%BB
		try {
			this.onRender();
		} catch (e) {
			console.error(e);
		}
	}

	onRender(): void {
	}

	onWindowKeyCMD(cmd: string, code: string, status: string, ev: KeyboardEvent): void {
		// console.debug('onWindowKey', cmd, code, status);
		// console.debug(ev,this.focus)
		if (cmd === 'Escape') {
			if (this.modal.onEscape()) {
				return;
			}
			if (this.contexMenu.clearCurrentContex()) {
				return;
			}
			// if (this.modal.onEscape()) { return; }
			if (this.popup.onEscape()) {
				return;
			}
			if (this.layerDlg.onEscape()) {
				return;
			}
			if (this.mode.onEscape()) {
				return;
			}
		} else if (code === 'Tab') {
			MainFrame.ins().onTab(ev?.shiftKey);
			// MainFrame.ins().leftWin.switchByTab();
		}
		// this.focus.onWindowKey(ev,status)
	}

	onWindowKey(ev: KeyboardEvent, status: string): void {
		this.onWindowKeyCMD(ev.key, ev.code, status, ev);
	}

	// focus end
	layerFrame: eui.UILayer;

	layerBottom: UILayer;

	layerDlg: PopupWinLayer;

	popup: PopupPanelLayer;

	// TOUCH_BEGIN
	contexMenu: MainContexMenu;

	layerTips: MainTips;

	layerClick: MainClick;

	showMainCommon(visible: boolean): void {
		// this.mainChat.visible = visible;
	}

	private createLayers(): void {
		const layer = getRightWindow().uiLayer;

		this.layerBottom = new UILayer();
		this.layerBottom.touchChildren = true;
		this.layerBottom.touchEnabled = false;
		layer.addChild(this.layerBottom);

		// layer.addChild(getRightWindow().toolsLayer);

		this.layerDlg = new PopupWinLayer();
		this.layerDlg.touchChildren = true;
		this.layerDlg.touchEnabled = false;
		layer.addChild(this.layerDlg);

		this.popup = new PopupPanelLayer();
		this.popup.touchChildren = true;
		this.popup.touchEnabled = false;
		layer.addChild(this.popup);

		this.modal = new MainModal(this);
		this.modal.touchChildren = true;
		this.modal.touchEnabled = false;
		layer.addChild(this.modal);


		this.layerTips = new MainTips(this);
		this.layerTips.touchChildren = true;
		this.layerTips.touchEnabled = false;
		layer.addChild(this.layerTips);

		this.contexMenu = new MainContexMenu(this);
		this.contexMenu.touchChildren = true;
		this.contexMenu.touchEnabled = false;
		this.addChild(this.contexMenu);
		// this.contexMenu.test()

		this.layerClick = new MainClick(this);
		this.layerClick.touchChildren = false;
		this.layerClick.touchEnabled = false;
		this.addChild(this.layerClick);

		this.cursor = new MainCursor(this);
		this.addChild(this.cursor);

		// this.addChild(game.UIWeather.ins());
		// fulllAlign(game.UIWeather.ins());
	}

	createFrame(): void {
		this.layerFrame = new eui.UILayer();
		this.layerFrame.touchChildren = true;
		this.layerFrame.touchEnabled = false;
		this.addChild(this.layerFrame);

		const mainFrame = MainFrame.ins();
		this.layerFrame.addChild(mainFrame);

		if (!mainFrame.isFull()) {
			mainFrame.toggleFull();
		}
	}

	onRightCreated(): void {
		this.createLayers();
	}
}

function getCursor(): MainCursor {
	return MainWindow.ins().cursor;
}

function getPopupLayer(): PopupLayer {
	return MainWindow.ins().popup;
}
